package com.scs.application.modules.wm.service;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.scs.application.core.query.QueryContext;
import com.scs.application.core.service.IBaseService;
import com.scs.application.modules.sys.model.RestResult;
import com.scs.application.modules.thirdparty.dto.his.HisHighQueryResult;
import com.scs.application.modules.thirdparty.request.convert.his.zhonglian.dto.HisStockQueryZhongLian;
import com.scs.application.modules.thirdparty.request.convert.his.zhonglian.dto.HisStockResultZhongLian;
import com.scs.application.modules.wm.dto.*;
import com.scs.application.modules.wm.entity.Stock;
import com.scs.application.modules.wm.enums.StockLockType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 库存 Service
 * </p>
 */
@Validated
public interface StockService extends IBaseService<Stock> {
    /**
     * 获取可用库存数量：分为虚拟锁库统计方式和实际批次锁库统计方式两种
     *
     * @param warehouseId：仓库ID
     * @param materialId：物料ID
     */
    Double getAvailableStock(String warehouseId, String materialId, StockLockType lockType);

    /**
     * @param warehouseId：仓库ID
     * @param materialId：物料ID
     * @param lot：批次
     * @return 可用库存列表
     */
    List<Stock> getAvailableStockList(String warehouseId, String materialId, String lot);

    /**
     * 分拆库存
     * 规则：非一物一码的才能分拆；分拆库存会导致库存以最小单位存储
     *
     * @param stock：库存实体
     * @param qty：分拆数量
     * @return 分拆后得到的库存ID
     */
    String splitStock(Stock stock, Double qty);

    /**
     * 合并库存：将制定的库存合并到类似库存下（同一个原始入库行号）
     *
     * @param stockId：库存ID
     */
    void mergeStock(String stockId);

    /**
     * 合并库存：将制定的库存合并到类似库存下（同一个原始入库行号）
     *
     * @param stock：库存实体
     */
    void mergeStock(Stock stock);

    /**
     * 打包
     * （打包后剩余的库存记录将被转换为最小单位存储）
     *
     * @param stockId：库存ID
     * @param unit：要加工的单位
     * @param packQty：加工数量
     * @param serialRuleCode：加工后生成码的规则
     * @return 加工结果库存列表
     */
    List<Stock> pack(String stockId, String unit, Integer packQty, String serialRuleCode);

    /**
     * 拆包
     * （拆包后的库存记录将被转换为最小单位存储）
     *
     * @param stockId：库存ID
     */
    void unpack(String stockId);

    /**
     * 通过唯一码查询库存
     *
     * @param uniqueCode：唯一码
     * @return his查询dto
     */
    HisStockDTO queryByUniqueCode(String uniqueCode);

    /**
     * 通过唯一码查询库存
     *
     * @param uniqueCode：唯一码
     * @return 库存实体
     */
    Stock getStockByUniqueCode(String uniqueCode);

    Stock getStockByUniqueCodeWithBusKeyValue(String uniqueCode, String busKeyValue);

    List<Stock> getStockListByUniqueCode(String uniqueCode);

    /**
     * 根据SNs获取库存列表(不查0库存)
     * @param sns
     * @param warehouseId
     * @return
     */
    List<Stock> getStockListBySns(List<String> sns, String warehouseId);

    /**
     * 通过唯一码查询库存及加工信息
     *
     * @param uc：唯一码
     * @param ucType：唯一码类型
     * @param warehouseId：仓库ID
     * @return {stock：库存记录，options：物料单位信息（加工选项）}
     */
    Map getProcessInfoByUC(String uc, String ucType, String warehouseId);

    /**
     * 通过入库单ID查询库存及加工信息
     *
     * @param workOrderId：唯一码
     * @return {stocks：库存记录s，options：物料单位信息（加工选项）}
     */
    Map getProcessInfoByWoId(String workOrderId);

    /**
     * 通过唯一码查询库存
     *
     * @param uc：唯一码
     * @param ucType：唯一码类型
     * @param warehouseId：仓库ID
     * @return 库存实体
     */
    Stock getStockByUC(String uc, String ucType, String warehouseId);

    /**
     * 上架
     *
     * @param rackingDTO：上架信息交换对象
     */
    void racking(RackingDTO rackingDTO);

    /**
     * 入库查找stockId
     *
     * @return
     */
    List<Stock> getStockByLineId(String lineId);


    void bindingRFID(String sn, String rfid);


    /**
     * 库存预警数据
     */
    List<StockDTO> getStockWarning();

    /**
     * 库存账龄TOP50数据
     */
    List<StockDTO> getStockDate();

    /**
     * 近效期库存TOP50数据
     */
    List<Stock> getStockExpDate();

    /**
     * 定数包消耗，病人消耗，选择耗材
     *
     * @param queryContext
     * @return
     */
    IPage pageForUse(QueryContext queryContext);


    /**
     * @Description：rfid绑定和解绑
     */
    void rfidBindOrUnbind(String sn, String rfid, String opType);

    /**
     * @Description：根据唯一码和类型查询库存
     */
    Stock getStockByUC(String uc);

    List<StockDTO> dtoList(QueryWrapper<Stock> wrapper);

     List<Stock> getStockByCode(String uniqueCode);

    /**
     * 定数包消耗红冲，病人消耗红冲，选择耗材
     *
     * @param queryContext
     * @return
     */
    IPage pageForRedType(QueryContext queryContext);

    Page<Map> pageForDemand(QueryContext context, Map<String, Object> userParam);

    List<Stock> getTcbstockInsertList();

    /**
     * 库存备份
     */
    String updateStockHistory();

    String updateOeAddStockZero();

    /**
     * 查询盘点仓库的库存
     */
    Page<Map> pageForStockCheck(QueryContext context, Map<String, Object> userParam);


    Page<Map> pageForPrint(QueryContext context);


    void updatePrintNum(JSONArray snArr);

    @Transactional(rollbackFor = Exception.class)
    /**
     * @Description： 上架
     */
    String upShelves(String uniqueCode);

    /**
     * @Description： 上架
     */
    RestResult upShelvesBatch(String warehouseId, String locationId);


    /**
     * 科室退货，选择耗材
     *
     * @param queryContext
     * @return
     */
    IPage pageDeptReturn(QueryContext queryContext, Map<String, Object> userParam);

    /**
     * 获取耗材货位
     *
     * @param matrId
     * @return
     */
    List<Map<String,Object>> getStockByMatr(String matrId);

    Page<Stock> pageForStockDiff(QueryContext context, Map<String, Object> userParam);

    String diffHandle(String type, String stockId);

    /**
     * @Description： 查询库存，同时也查询0库存表，一般用于科室退货、供应商退货、his退费、科室冲红等反向添加库存业务
     * @param queryWrapper 查询条件
     * @param userParam     特殊条件，预留
     */
    List<Stock> listStockWithZero(QueryWrapper queryWrapper, Map<String, Object> userParam);

    /**
     * @Description： 查询库存，同时也查询0库存表，一般用于科室退货、供应商退货、his退费、科室冲红等反向添加库存业务
     * @param id
     */
    Stock getByIdWithZero(String id);

    Page<Map> pageStockWithZero(QueryContext context, Map<String, Object> userParam);
    //耗材停用
    RestResult syncHrpMatrStop();

    List<StockGroupWarehouseMatrDTO> getListGroupByMatr(QueryWrapper queryWrapper);

    List<Stock> getStockListByUdi(String udi);

    void udiBindOrUnbind(String sn, String udi, String opType);

    HisHighQueryResult queryByUniqueCodeFoHis(String uniqueCode);

    QueryWrapper getStockQueryWrapper(String uniqueCode);

    /**
     * <p>根据唯一码：SN集合 获取库存集合信息</p>
     * <p>验证库存有效期</p>
     *
     * @param sns: SN集合
     * @return {@link Stock} 集合
     */
    List<Stock> getExpStockByUC(@NotEmpty(message = "SN集合不能为空") List<String> sns);

    /**
     * <p>根据唯一码：SN、RFID、UDI 获取库存信息</p>
     * <p>验证库存有效期</p>
     *
     * @param uc: 唯一码，支持 SN、RFID、UDI
     * @return {@link Stock} 库存对象
     */
    Stock getExpStockByUC(@NotBlank(message = "唯一码不能为空") String uc);

    /**
     * <p>根据库存ID 获取库存信息</p>
     *
     * @param id:             库存ID
     * @param customValidate: 使用自定义验证
     * @return {@link Stock} 库存对象
     */
    Stock getExpStockById(@NotBlank(message = "ID不能为空") String id, boolean customValidate);

    /**
     * <p>根据库存ID集合 获取库存信息</p>
     * @param ids:库存ID集合
     * @return {@link Stock} 集合
     */
    List<Stock> getExpStockById(@NotEmpty(message = "ID集合不能为空") List<String> ids);

    //获取需要推送给HIS的库存
    String pushHis();

    String excelImportForImportStock(MultipartFile file, Map<String, String> reqData);

    List<HisStockResultZhongLian> queryByUniqueCodeListFoHisZl(List<HisStockQueryZhongLian> queryList);
}
